﻿
/*
// 友元、
#include<iostream>
using namespace std;

class Date
{
	//友元函数需要在类中声明
	friend void f(Date& d); // 友元函数
public:
	Date(int year = 1, int month = 1, int day = 1)
		:_year(year)
		,_month(month)
		,_day(day)
	{}

	void Print()
	{
		cout << _year << "-" << _month << "-" << _day << endl;
	}
private:
	// c++11 才支持 声明的时候给一个缺省值
	int _year = 2024; // 这里不是定义，是缺省值，如果构造函数没有定义这个变量，那就调用缺省值
	int _month = 6;
	int _day = 2;
};

// 正常来说如果我们想在类外边访问类中私有的成员变量，是做不到的
// 但是如果有友元的存在就可以
void f(Date& d)
{
	d._year = 2024;
	cout << d._year << endl;
}

int main()
{
	Date d1;
	d1.Print();

	f(d1);
	return 0;
}
*/

/*
// 其实上述场景友元并不是必须的，我们在类中在定义一个成员函数也可以解决
// 我们来看一个必须用到友元的场景:  cout << d1 的重载
// cout 是 ostream 类型
#include<iostream>
using namespace std;

class Date
{
	friend ostream& operator<<(ostream& out, const Date& d);
public:
	Date(int year = 1, int month = 1, int day = 1)
		:_year(year)
		, _month(month)
		, _day(day)
	{}

	ostream& operator<<(ostream& out) // this指针形参无法修改顺序
	{
		out << _year << "/" << _month << "/" << _day << endl;
		return out;
	}
private:
	// c++11 才支持 声明的时候给一个缺省值
	int _year = 2024; // 这里不是定义，是缺省值，如果构造函数没有定义这个变量，那就调用缺省值
	int _month = 6;
	int _day = 2;
};

ostream& operator<<(ostream& out, const Date& d)
{
	//通过友元来实现对类内成员变量的访问
	out << d._year << "/" << d._month << "/" << d._day << endl;
	return out;
}


int main()
{
	Date d1;
	Date d2(2024, 6, 2);
	// 我们知道 涉及到自定义类的运算符都要重载
	//cout << d1; // 我们发现，即便重载了 输出运算符 仍然编译报错
	// 因为这里会编译成 cout.operator<<(d1) 而我们期望的是d1.operator<<(cout)
	d1 << cout; // 1/1/1  这里就可以输出了，但是这个格式不是我们期望的
	// 但是由于this指针形参是隐含的，因此我们无法修改其顺序

	// 这个时候友元就出场了
	cout << d1;// 1/1/1 
	cout << d1 << d2; // 有连等的使用场景 返回值需要是ostream类型的
	//1/1/1
	//2024/6/2
	cout << d1 << "->" << endl << d2;
	//1/1/1
	//->
	//2024/6/2

	return 0;
}
*/

/*
// 学会了cout << d1 的重载 那么 cin >> d1 的重载也是一样的道理
// cin 是 istream 类型的一个全局变量
#include<iostream>
using namespace std;

class Date
{
	friend ostream& operator<<(ostream& out, const Date& d);

	friend istream& operator>>(istream& out, Date& d);

public:
	Date(int year = 1, int month = 1, int day = 1)
		:_year(year)
		, _month(month)
		, _day(day)
	{}

private:
	// c++11 才支持 声明的时候给一个缺省值
	int _year = 2024; 
	int _month = 6;
	int _day = 2;
};

ostream& operator<<(ostream& out, const Date& d)
{
	//通过友元来实现对类内成员变量的访问
	out << d._year << "/" << d._month << "/" << d._day << endl;
	return out;
}

int GetMonthDay(int year, int month)
{
	// 给13  恰好让下标对上 月份
	int day[13] = { 0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };

	// 判断是否是闰年
	if (month == 2 && (year % 4 == 0 && year % 100 != 0) || year % 400 == 0)
		day[2] = 29;

	return day[month];
}

istream& operator>>(istream& in, Date& d)
{
	int year, month, day;

	cout << "请输入年份" << endl;
	in >> year;
	if (year > 0) // 判断输入的年是否合法
		d._year = year;
	else
	{
		cout << "非法年份的输入" << endl;
		return in;
	}

	cout << "请输入月份" << endl;
	in >> month;
	if (month > 0 && month < 13) // 判断输入的月是否合法
		d._month = month;
	else
	{
		cout << "非法月份的输入" << endl;
		return in;
	}

	cout << "请输入日" << endl;
	in >> day;
	if (day > 0 && day < GetMonthDay(d._year, d._month)) // 判断日是否合法
		d._day = day;
	else
	{
		cout << "非法日的输入" << endl;
		return in;
	}

	return in;
}

int main()
{
	Date d1, d2;

	cin >> d1 >> d2; // cin.operator>>(cin, d1)

	cout << d1 << d2;

	return 0;
}
*/

// 友元类
class Time
{
	friend class Date;// 声明日期类为时间类的友元类，则在日期类中就直接访问Time类中的私有成员变量
public:
	Time(int hour = 0, int minute = 0, int second = 0)
		: _hour(hour)
		, _minute(minute)
		, _second(second)
	{}

private:
	int _hour;
	int _minute;
	int _second;
};

// 我们的Date类需要经常访问Time类的成员
// 如果一个一个都搞成友元函数有点麻烦
// 这个时候友元类就派上用场了
class Date
{
public:
	Date(int year = 1900, int month = 1, int day = 1)
		: _year(year)
		, _month(month)
		, _day(day)
	{
		_t = 1;
	}

	void SetTimeOfDate(int hour, int minute, int second)
	{
		// 直接访问时间类私有的成员变量
		_t._hour = hour;
		_t._minute = minute;
		_t._second = second;
	}

private:
	int _year;
	int _month;
	int _day;
	Time _t;
};


int main()
{

	return 0;
}